use chrono::Local;
use serde::{Deserialize, Deserializer, Serialize};
use serde_json::Value;
use crate::db::{get_db, Weibo};
use crate::error::{AppError, Response};

#[derive(Serialize,Deserialize)]
pub struct WeiboNew{
    ok:Option<usize>,
    data: Option<WeiboNewData>,
}

#[derive(Serialize,Deserialize, Clone, Debug)]
pub struct WeiboNewData{
    mapi:Option<Vec<String>>,
    cards:Option<Vec<WeiboNewDataCard>>,
}

#[derive(Serialize,Deserialize, Clone, Debug)]
struct WeiboNewDataCard{
    show_type: Option<usize>,
    card_type: Option<usize>,
    title:Option<String>,
    itemid: Option<String>,
    card_group: Option<Vec<WeiboNewDataCardGroup>>
}

#[derive(Serialize,Deserialize, Clone, Debug)]
struct WeiboNewDataCardGroup {
    icon:Option<String>,
    icon_height: Option<usize>,
    icon_width: Option<usize>,
    schema: Option<String>,
    itemid: Option<String>,
    card_type: Option<usize>,
    pic: Option<String>,
    actionlog: Option<WeiboNewDataCardActionLog>,
    desc: Option<String>,
    #[serde(deserialize_with = "number_to_string",default)]
    desc_extr: Option<String>,
}



fn number_to_string<'de,D>(deser: D) -> Result<Option<String>,D::Error>
where D:Deserializer<'de>
{
    let v = serde_json::Value::deserialize(deser);
    match v {
        Ok(v) => {
            match v {
                Value::Number(n) => Ok(Some(n.to_string())),
                Value::String(s) => Ok(Some(s)),
                _ => Ok(None),
            }
        },
        Err(e) => Ok(None)
    }

}


#[derive(Serialize,Deserialize, Clone, Debug)]
struct WeiboNewDataCardActionLog {
    lfid: Option<String>,
    unicode: Option<String>,
    ext: Option<String>,
    act_type: Option<usize>,
    fid: Option<String>,
    act_code: Option<usize>,
    luicode: Option<String>,
}

// 构建请求
pub async fn request(url: &str) -> Result<(), AppError> {
    let db = get_db();

    let resp = reqwest::get(url).await?;
    let weibo_new = resp.text().await?;
    let uuid = uuid::Uuid::now_v7().to_string();

    let now = Local::now();
    let now = now.format("%Y-%m-%d %H:%M:%S%.3f").to_string();

    println!("{}",&weibo_new);
    let _r = sqlx::query("insert into tb_weibo (id,info,insert_time) values (?,?,?)")
        .bind(&uuid)
        .bind(&weibo_new)
        .bind(&now)
        .execute(db.as_ref()).await?;
    Ok(())
}

pub async fn update_weibo_new() -> Result<(),AppError> {
    let url = "https://m.weibo.cn/api/container/getIndex?containerid=106003type%3D25%26t%3D3%26disable_hot%3D1%26filter_type%3Drealtimehot";
    let _result = request(url).await?;
    Ok(())
}

#[tauri::command]
pub async fn update_weibo(){
    let _ = update_weibo_new().await.unwrap();
}


#[tauri::command]
pub async fn get_news_from_weibo_hot() -> Result<Response<WeiboNew>,AppError> {
    let db = get_db();
    
    let result = sqlx::query_as::<_,Weibo>("
        SELECT
            id,
            info,
            insert_time
        from (
            select
                id,
                info,
                insert_time,
                ROW_NUMBER () over(order by insert_time desc) as rn
            from tb_weibo
        ) t
        where rn=1
        "
    ).fetch_one(db.as_ref()).await?;


    println!("{:?}",&result.info);
    let w = serde_json::from_str::<WeiboNew>(&result.info)?;


    let rs = Response::new("200".to_string(),"成功".to_string(),w);
    Ok(rs)
}